/////////////////////////////////////////////////////////////////////////////
// Original code from libhdfs3. Copyright (c) 2013 - 2014, Pivotal Inc.
// All rights reserved. Author: Zhanwei Wang
/////////////////////////////////////////////////////////////////////////////
//  Modifications by Kumo Inc.
// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//



#pragma once


#include <kmhdfs/common/exception.h>
#include <kmhdfs/common/exception_internal.h>
#include <functional>
#include <turbo/log/logging.h>
#include <kmhdfs/common/xml_config.h>

#include <cassert>
#include <vector>

namespace Hdfs {
    namespace Internal {
        template<typename T>
        struct ConfigDefault {
            T *variable; //variable this configure item should be bound to.
            const char *key; //configure key.
            T value; //default value.
            std::function<void(const char *, T const &)> check; //the function to validate the value.
        };

        class SessionConfig {
        public:
            SessionConfig(const Config &conf);

            /*
             * rpc configure
             */

            int32_t getRpcConnectTimeout() const {
                return rpcConnectTimeout;
            }

            int32_t getRpcMaxIdleTime() const {
                return rpcMaxIdleTime;
            }

            int32_t getRpcMaxRetryOnConnect() const {
                return rpcMaxRetryOnConnect;
            }

            void setRpcMaxRetryOnConnect(int32_t rpcMaxRetryOnConnect) {
                this->rpcMaxRetryOnConnect = rpcMaxRetryOnConnect;
            }

            int32_t getRpcPingTimeout() const {
                return rpcPingTimeout;
            }

            int32_t getRpcReadTimeout() const {
                return rpcReadTimeout;
            }

            bool isRpcTcpNoDelay() const {
                return rpcTcpNoDelay;
            }

            int32_t getRpcWriteTimeout() const {
                return rpcWriteTimeout;
            }

            /*
             * FileSystem configure
             */
            const std::string &getDefaultUri() const {
                return defaultUri;
            }

            int32_t getDefaultReplica() const {
                return defaultReplica;
            }

            int64_t getDefaultBlockSize() const {
                return defaultBlockSize;
            }

            /*
             * InputStream configure
             */
            int32_t getLocalReadBufferSize() const {
                return localReadBufferSize;
            }

            int32_t getInputReadTimeout() const {
                return inputReadTimeout;
            }

            int32_t getInputWriteTimeout() const {
                return inputWriteTimeout;
            }

            int32_t getInputConnTimeout() const {
                return inputConnTimeout;
            }

            int32_t getPrefetchSize() const {
                return prefetchSize;
            }

            bool isReadFromLocal() const {
                return readFromLocal;
            }

            int32_t getMaxGetBlockInfoRetry() const {
                return maxGetBlockInfoRetry;
            }

            int32_t getMaxLocalBlockInfoCacheSize() const {
                return maxLocalBlockInfoCacheSize;
            }

            bool connectViaHostname() const {
                return connectToDnViaHostname;
            }

            /*
             * OutputStream configure
             */
            int32_t getDefaultChunkSize() const {
                return chunkSize;
            }

            int32_t getDefaultPacketSize() const {
                if (packetSize % chunkSize != 0) {
                    THROW(HdfsConfigInvalid,
                          "output.default.packetsize should be larger than 0 "
                          "and be the multiple of output.default.chunksize.");
                }

                return packetSize;
            }

            int32_t getBlockWriteRetry() const {
                return blockWriteRetry;
            }

            int32_t getOutputConnTimeout() const {
                return outputConnTimeout;
            }

            int32_t getOutputReadTimeout() const {
                return outputReadTimeout;
            }

            int32_t getOutputWriteTimeout() const {
                return outputWriteTimeout;
            }

            bool canAddDatanode() const {
                return addDatanode;
            }

            int32_t getHeartBeatInterval() const {
                return heartBeatInterval;
            }

            int32_t getRpcMaxHaRetry() const {
                return rpcMaxHARetry;
            }

            void setRpcMaxHaRetry(int32_t rpcMaxHaRetry) {
                rpcMaxHARetry = rpcMaxHaRetry;
            }

            const std::string &getRpcAuthMethod() const {
                return rpcAuthMethod;
            }

            void setRpcAuthMethod(const std::string &rpcAuthMethod) {
                this->rpcAuthMethod = rpcAuthMethod;
            }

            const std::string &getKerberosCachePath() const {
                return kerberosCachePath;
            }

            void setKerberosCachePath(const std::string &kerberosCachePath) {
                this->kerberosCachePath = kerberosCachePath;
            }

            int32_t getRpcSocketLingerTimeout() const {
                return rpcSocketLingerTimeout;
            }

            void setRpcSocketLingerTimeout(int32_t rpcSocketLingerTimeout) {
                this->rpcSocketLingerTimeout = rpcSocketLingerTimeout;
            }

            void setLogSeverity(const std::string &logSeverityLevel) {
                this->logSeverity = logSeverityLevel;
            }

            int32_t getPacketPoolSize() const {
                return packetPoolSize;
            }

            void setPacketPoolSize(int32_t packetPoolSize) {
                this->packetPoolSize = packetPoolSize;
            }

            int32_t getCloseFileTimeout() const {
                return closeFileTimeout;
            }

            void setCloseFileTimeout(int32_t closeFileTimeout) {
                this->closeFileTimeout = closeFileTimeout;
            }

            int32_t getRpcTimeout() const {
                return rpcTimeout;
            }

            void setRpcTimeout(int32_t rpcTimeout) {
                this->rpcTimeout = rpcTimeout;
            }

            bool doesNotRetryAnotherNode() const {
                return notRetryAnotherNode;
            }

            void setIFNotRetryAnotherNode(bool notRetryAnotherNode) {
                this->notRetryAnotherNode = notRetryAnotherNode;
            }

            int32_t getMaxReadBlockRetry() const {
                return maxReadBlockRetry;
            }

            void setMaxReadBlockRetry(int32_t maxReadBlockRetry) {
                this->maxReadBlockRetry = maxReadBlockRetry;
            }

            bool doUseMappedFile() const {
                return useMappedFile;
            }

            void setUseMappedFile(bool useMappedFile) {
                this->useMappedFile = useMappedFile;
            }

            bool isLegacyLocalBlockReader() const {
                return legacyLocalBlockReader;
            }

            void setLegacyLocalBlockReader(bool legacyLocalBlockReader) {
                this->legacyLocalBlockReader = legacyLocalBlockReader;
            }

            const std::string &getDomainSocketPath() const {
                return domainSocketPath;
            }

            void setDomainSocketPath(const std::string &domainSocketPath) {
                this->domainSocketPath = domainSocketPath;
            }

            int32_t getMaxFileDescriptorCacheSize() const {
                return maxFileDescriptorCacheSize;
            }

            void setMaxFileDescriptorCacheSize(int32_t maxFileDescriptorCacheSize) {
                this->maxFileDescriptorCacheSize = maxFileDescriptorCacheSize;
            }

            int32_t getSocketCacheExpiry() const {
                return socketCacheExpiry;
            }

            int32_t getSocketCacheCapacity() const {
                return socketCacheCapacity;
            }

            int32_t getStripeReaderThreadPoolSize() const {
                return stripeReaderThreadPoolSize;
            }

        public:
            /*
             * rpc configure
             */
            int32_t rpcMaxIdleTime;
            int32_t rpcPingTimeout;
            int32_t rpcConnectTimeout;
            int32_t rpcReadTimeout;
            int32_t rpcWriteTimeout;
            int32_t rpcMaxRetryOnConnect;
            int32_t rpcMaxHARetry;
            int32_t rpcSocketLingerTimeout;
            int32_t rpcTimeout;
            bool rpcTcpNoDelay;
            std::string rpcAuthMethod;

            /*
             * FileSystem configure
             */
            std::string defaultUri;
            std::string kerberosCachePath;
            std::string logSeverity;
            int32_t defaultReplica;
            int64_t defaultBlockSize;

            /*
             * InputStream configure
             */
            bool connectToDnViaHostname;
            bool useMappedFile;
            bool readFromLocal;
            bool notRetryAnotherNode;
            bool legacyLocalBlockReader;
            int32_t inputConnTimeout;
            int32_t inputReadTimeout;
            int32_t inputWriteTimeout;
            int32_t localReadBufferSize;
            int32_t maxFileDescriptorCacheSize;
            int32_t maxGetBlockInfoRetry;
            int32_t maxLocalBlockInfoCacheSize;
            int32_t maxReadBlockRetry;
            int32_t prefetchSize;
            int32_t socketCacheCapacity;
            int32_t socketCacheExpiry;
            std::string domainSocketPath;
            int32_t stripeReaderThreadPoolSize;

            /*
             * OutputStream configure
             */
            bool addDatanode;
            int32_t chunkSize;
            int32_t packetSize;
            int32_t blockWriteRetry; //retry on block not replicated yet.
            int32_t outputConnTimeout;
            int32_t outputReadTimeout;
            int32_t outputWriteTimeout;
            int32_t packetPoolSize;
            int32_t heartBeatInterval;
            int32_t closeFileTimeout;
        };
    }
}
